/**
 * @ClassName KP23_bitAddMinusMultiDiv
 * @Description: TODO
 * @Author: JCC
 * @CreateTime: 2023/10/17 10:39
 */

/**
 * 位运算实现加减乘除
 */
public class KP23_bitAddMinusMultiDiv {
    // 加法
    public static int add(int a, int b) {
        int sum = 0;
        while (b != 0) {
            sum = a ^ b;
            b = (a & b) << 1;
            a = sum;
        }
        return sum;
    }

    public static int opNum(int a) {
        return add(~a, 1);
    }

    // 减法
    public static int sub(int a, int b) {
        return add(a, opNum(b));
    }

    public static boolean isNeg(int num) {
        return (num & (1 << 31)) != 0;
    }

    // 乘法

    /**
     * 此过程有点复杂
     *
     * @param a
     * @param b
     * @return
     */
    public static int mul(int a, int b) {
        // true 表示同号 false表示异号
        boolean flag = true;
        if (!isNeg(a) && isNeg(b)) {
            b = opNum(b);
            flag = false;
        } else if (isNeg(a) && !isNeg(b)) {
            a = opNum(a);
            flag = false;
        } else if (isNeg(a) && isNeg(b)) {
            a = opNum(a);
            b = opNum(b);
        }
        int ret = 0;
        while (b != 0) {
            if ((b & 1) != 0) {
                ret = add(ret, a);
            }
            b >>>= 1;
            a <<= 1;
        }
        if (!flag) {
            ret = opNum(ret);
        }
        return ret;
    }

    /**
     * 上面方法的优化
     *
     * @param a
     * @param b
     * @return
     */
    public static int myMul(int a, int b) {
        int ret = 0;
        while (b != 0) {
            if ((b & 1) != 0) {
                ret = add(ret, a);
            }
            a <<= 1;
            // 无符号右移，是负数的话，如果是>>1,有符号右移就会一直死循环
            b >>>= 1;
        }
        return ret;
    }

    // 除法

    /**
     * a / b = c
     * ? / b = 001101
     * ? = b*2^0 + b*2^2 + b*2^3
     * a / b = ?
     * (((a - b*2^?) - b*2^??) - b*2^???) ...
     * a1 = (a - b*2^?)
     * a2 = (a1 - b*2^??)...
     * 每次b*2^?都不能超过得到的a
     *
     * @param a
     * @param b
     * @return
     */
    public static int divide(int a, int b) {
        int x = isNeg(a) ? opNum(a) : a;
        int y = isNeg(b) ? opNum(b) : b;
        int ret = 0;
        for (int i = 30; i >= 0; i = sub(i,1)) {
            if ((x >> i) >= y) {
                x = sub(x,y << i);
                ret = add(ret,1 << i);
            }
        }
        return isNeg(a) && isNeg(b) || !isNeg(a) && !isNeg(b) ? ret : opNum(ret);
    }

    public static int div(int a, int b) {
        if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {
            return 1;
        } else if (a == Integer.MIN_VALUE) {
            if (b == -1) {
                return Integer.MAX_VALUE;
            } else {
                int ret = divide(add(a,1),b);
                return add(ret,div(sub(a,mul(ret,b)),b));
            }
        } else if (b == Integer.MIN_VALUE) {
            return 0;
        } else {
            return divide(a,b);
        }
    }

    /**
     * 测试加减乘除
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(div(Integer.MAX_VALUE,Integer.MAX_VALUE));
        System.out.println(div(Integer.MIN_VALUE,Integer.MIN_VALUE));
        System.out.println(div(Integer.MIN_VALUE,-1));
        System.out.println(div(Integer.MIN_VALUE,512));
        System.out.println(div(1341634,Integer.MIN_VALUE));
        System.out.println(div(-512,-4));
    }

    public static void main1(String[] args) {
        System.out.println(mul(3, -18));
        System.out.println(myMul(3, -18));
        System.out.println("===========================");
        System.out.println(mul(5, 14));
        System.out.println(myMul(5, 14));
        System.out.println("===========================");
        System.out.println(mul(-5, -14));
        System.out.println(myMul(-5, -14));
        System.out.println("===========================");
        System.out.println(mul(-5, 14));
        System.out.println(myMul(-5, 14));
    }

    public static void main0(String[] args) {
        int sum = add(109, 299);
        System.out.println(sum);
        System.out.println(opNum(-390));
        System.out.println("===========================");
        System.out.println(Integer.MAX_VALUE);
        System.out.println(opNum(Integer.MAX_VALUE));
        System.out.println("===========================");
        System.out.println(0);
        System.out.println(opNum(0));
        System.out.println("===========================");
        System.out.println(Integer.MIN_VALUE);
        System.out.println(opNum(Integer.MIN_VALUE));
        System.out.println("===========================");
        System.out.println(add(Integer.MAX_VALUE, 1));
        System.out.println("===========================");
        System.out.println(mul(3, -18));
        System.out.println(myMul(3, -18));
    }
}
